﻿#region Copyright (c) 2012-10, Olaf Kober <amarok.projects@gmail.com>
//================================================================================
//	Permission is hereby granted, free of charge, to any person obtaining a copy
//	of this software and associated documentation files (the "Software"), to deal
//	in the Software without restriction, including without limitation the rights
//	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//	copies of the Software, and to permit persons to whom the Software is
//	furnished to do so, subject to the following conditions:
//
//	The above copyright notice and this permission notice shall be included in
//	all copies or substantial portions of the Software.
//
//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//	THE SOFTWARE.
//================================================================================
#endregion

#if TESTS

using System;
using NUnit.Framework;


namespace Amarok
{
	[TestFixture]
	public class Test_Identity
	{
		[Serializable]
		private class DummyIdentity : Identity
		{
			public override Boolean Equals(Object other)
			{
				return true;
			}

			public override Int32 GetHashCode()
			{
				return 1234;
			}
		}

		private class TestIdentity : Identity
		{
			public static Int32 EqualsCalled;
			public static Int32 GetHashCodeCalled;


			public override Boolean Equals(Object other)
			{
				EqualsCalled++;
				return false;
			}
			public override Int32 GetHashCode()
			{
				GetHashCodeCalled++;
				return -1;
			}
		}

		private class IncorrectlyImplementedIdentity : Identity
		{
		}

		[SetUp]
		public void Setup()
		{
			TestIdentity.EqualsCalled = 0;
			TestIdentity.GetHashCodeCalled = 0;
		}


		// --- TESTS ---


		[Test]
		public void Test_Equals()
		{
			TestIdentity testid = new TestIdentity();
			Assert.AreEqual(false, testid.Equals(123));
			Assert.AreEqual(1, TestIdentity.EqualsCalled);

			Identity id = testid;
			Assert.AreEqual(false, id.Equals("AAA"));
			Assert.AreEqual(2, TestIdentity.EqualsCalled);

			Object obj = testid;
			Assert.AreEqual(false, obj.Equals("AAA"));
			Assert.AreEqual(3, TestIdentity.EqualsCalled);
		}

		[Test]
		public void Test_GetHashCode()
		{
			TestIdentity testid = new TestIdentity();
			Assert.AreEqual(-1, testid.GetHashCode());
			Assert.AreEqual(1, TestIdentity.GetHashCodeCalled);

			Identity id = testid;
			Assert.AreEqual(-1, id.GetHashCode());
			Assert.AreEqual(2, TestIdentity.GetHashCodeCalled);

			Object obj = testid;
			Assert.AreEqual(-1, obj.GetHashCode());
			Assert.AreEqual(3, TestIdentity.GetHashCodeCalled);
		}

		[Test]
		public void Test_Operator_Equal()
		{
			TestIdentity testidA = new TestIdentity();
			TestIdentity testidB = new TestIdentity();

			Assert.AreEqual(false, testidA == testidB);
			Assert.AreEqual(1, TestIdentity.EqualsCalled);	// called

			Assert.AreEqual(false, (Identity)testidA == (Identity)testidB);
			Assert.AreEqual(2, TestIdentity.EqualsCalled);	// called

			Assert.AreEqual(false, (Object)testidA == (Object)testidB);
			Assert.AreEqual(2, TestIdentity.EqualsCalled);	// not called
		}

		[Test]
		public void Test_Operator_Unequal()
		{
			TestIdentity testidA = new TestIdentity();
			TestIdentity testidB = new TestIdentity();

			Assert.AreEqual(true, testidA != testidB);
			Assert.AreEqual(1, TestIdentity.EqualsCalled);	// called

			Assert.AreEqual(true, (Identity)testidA != (Identity)testidB);
			Assert.AreEqual(2, TestIdentity.EqualsCalled);	// called

			Assert.AreEqual(true, (Object)testidA != (Object)testidB);
			Assert.AreEqual(2, TestIdentity.EqualsCalled);	// not called
		}

		[Test]
		[ExpectedException(typeof(InvalidOperationException))]
		public void Test_Incorrectly_Implemented_Equals()
		{
			Identity id = new IncorrectlyImplementedIdentity();
			id.Equals(123);
		}

		[Test]
		[ExpectedException(typeof(InvalidOperationException))]
		public void Test_Incorrectly_Implemented_GetHashCode()
		{
			Object obj = new IncorrectlyImplementedIdentity();
			obj.GetHashCode();
		}

		[Test]
		public void Test_Serialization_BinaryFormatter()
		{
			DummyIdentity objectA = new DummyIdentity();
			DummyIdentity objectB = TestHelper.TestBinaryFormatterRoundtrip<DummyIdentity>(objectA);

			Assert.AreNotSame(objectA, objectB);
		}

		[Test]
		public void Test_Serialization_DataContract()
		{
			DummyIdentity objectA = new DummyIdentity();
			DummyIdentity objectB = TestHelper.TestDataContractRoundtrip<DummyIdentity>(objectA);

			Assert.AreNotSame(objectA, objectB);
		}

	}
}

#endif
